#include "HttpUtil.h"

HttpUtil* HttpUtil::singleObjPtr = nullptr;

void HttpUtil::Init()
{
    httplib::Server server;

    //获取摄像头flv流
    server.Post("/AlarmExport", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        std::string resContentStr;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::AlarmExport(resContentStr, reqContent);
        else resContentStr = resContent.toStyledString();
        res.set_header("Content-Disposition", "attachment; filename=\"export.csv\"");
        res.set_content(resContentStr, "application/octet-stream");
    });

    //获取摄像头flv流
    server.Post("/GetCameraFlv", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetCameraFlv(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //停止摄像头flv流
    server.Post("/CloseCameraFlv", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::StopCameraFlv(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //登录功能
    server.Post("/LogIn", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, false, true, reqContent, resContent)) == 200) HttpApi::LogIn(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取所有摄像头信息
    server.Get("/GetAllCameraConfig", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, false, reqContent, resContent)) == 200) HttpApi::DataBaseOperation(resContent, {}, "CameraConfig", "Query");
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取所有算法信息
    server.Get("/GetAllAlgorithmConfig", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, false, reqContent, resContent)) == 200) HttpApi::DataBaseOperation(resContent, {}, "AlgorithmConfig", "Query");
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取当前用户信息
    server.Get("/GetCurUser", [](const httplib::Request& req, httplib::Response& res) {
        ReqPrint(req);
        Json::Value resContent;
        Json::Value reqContent;
        UserInfo userInfo;
        if(LogInJudge(req, resContent, userInfo))
        {
            Json::Value condition;
            condition["UserID"] = userInfo.userID;
            HttpApi::GetUser(resContent, condition);
            res.status = 200;
        }
        else res.status = 401;

        res.set_content(resContent.toStyledString(), "application/json");
        std::cout << "返回状态码:" << res.status << std::endl << std::endl;
    });

    //获取指定用户信息
    server.Post("/GetUser", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetUser(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //添加所有数据库的增删改查
    std::vector<std::string> allTableNames = {"CameraConfig", "AlgorithmConfig", "AlarmInfo", "UserInfo", "RoleConfig", "AreaConfig",
        "AlarmTypeConfig", "AlarmHandleConfig", "AlarmTemplateConfig", "MenuConfig", "DictionaryConfig", "LogInfo"};
    std::vector<std::string> allOperationNames = {"Add", "Delete", "Edit", "Query"};
    for (size_t i = 0; i < allTableNames.size(); i++)
    {
        for (size_t j = 0; j < allOperationNames.size(); j++)
        {
            std::string url = "/DbOperation/" + allTableNames[i] + "/" + allOperationNames[j];
            if(url == "/DbOperation/AlarmInfo/Add" || url == "/DbOperation/AlgorithmConfig/Delete") continue;

            //获取指定用户信息
            server.Post(url, [](const httplib::Request& req, httplib::Response& res) {
                Json::Value resContent;
                Json::Value reqContent;
                if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200)
                {
                    std::vector<std::string> urls = Tools::Split(req.path, '/');
                    HttpApi::DataBaseOperation(resContent, reqContent, urls[2], urls[3]);
                }
                res.set_content(resContent.toStyledString(), "application/json");
            });
        }
    }
    
    //查询所有摄像头是否携带指定算法
    server.Post("/HasAlgorithm", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::HasAlgorithm(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //更新所有摄像头对特定算法的绑定
    server.Post("/UpdateAlgorithmBinding", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::UpdateAlgorithmBinding(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //删除算法
    server.Post("/AlgorithmDelete", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::AlgorithmDelete(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //添加报警
    server.Post("/AddAlarm", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::AddAlarm(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //报警处理
    server.Post("/AlarmHandle", [](const httplib::Request& req, httplib::Response& res) {
        ReqPrint(req);
        Json::Value resContent;
        Json::Value reqContent;
        UserInfo userInfo;
        if(LogInJudge(req, resContent, userInfo))
        {
            if(ReqContentAnalysis(req.body, reqContent, resContent))
            {
                HttpApi::AlarmHandle(resContent, reqContent, userInfo);
                res.status = 200;
            }
            else res.status = 400;
        }
        else res.status = 401;

        res.set_content(resContent.toStyledString(), "application/json");
        std::cout << "返回状态码:" << res.status << std::endl << std::endl;
    });

    //报警时间统计
    server.Post("/GetAlarmStatisticsTime", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetAlarmStatistics(resContent, reqContent, true);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //报警类型统计
    server.Post("/GetAlarmStatisticsRatio", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetAlarmStatistics(resContent, reqContent, false);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取菜单属树形图
    server.Post("/GetMenuTree", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetMenuTree(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取区域属树形图
    server.Post("/GetAreaTree", [](const httplib::Request& req, httplib::Response& res) {
        Json::Value resContent;
        Json::Value reqContent;
        if((res.status = ReqPreprocess(req, true, true, reqContent, resContent)) == 200) HttpApi::GetAreaTree(resContent, reqContent);
        res.set_content(resContent.toStyledString(), "application/json");
    });

    //获取报警图片
    server.Get("/AlarmPic(.*)", [](const httplib::Request& req, httplib::Response& res) {
        std::string file_path = req.matches[1]; 
        Json::Value resContent;
        std::string content;
        std::string contentType;
        if(!HttpApi::GetAlarmImage(content, file_path, contentType))
        {
            res.status = 404;
            content = "";
        }
        else res.status = 200;

        res.set_content(content, contentType);
    });

    std::cout << "服务端成功运行于端口" << ":18080" << std::endl;
    server.listen("0.0.0.0", 18080);
}

int HttpUtil::ReqPreprocess(const httplib::Request& req, bool UserCheck, bool ContentCheck, Json::Value& reqContent, Json::Value& errorRes)
{
    ReqPrint(req);
    if(UserCheck && !LogInJudge(req, errorRes))
    {
        std::cout << "返回状态码:" << 401 << std::endl << "====================================" << std::endl << std::endl;
        return 401;
    }

    if(ContentCheck && !ReqContentAnalysis(req.body, reqContent, errorRes))
    {
        std::cout << "返回状态码:" << 400 << std::endl << "====================================" << std::endl << std::endl;
        return 400;
    }

    std::cout << "返回状态码:" << 200 << std::endl << "====================================" << std::endl << std::endl;
    return 200;
}

void HttpUtil::ReqPrint(const httplib::Request& req)
{
    time_t rawtime;
    struct tm* timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    std::cout << "====================================" << std::endl;
    std::cout << asctime(timeinfo);
    std::cout << "Request received :\n" << req.method << " " << req.path << std::endl << std::endl << req.body << std::endl;
    std::cout << "------------------------------------" << std::endl;
}

bool HttpUtil::LogInJudge(const httplib::Request& req, Json::Value& errorRes, UserInfo& userInfo)
{
    std::string token = req.get_header_value("Token");

    if(HttpApi::accessIds.find(token) != HttpApi::accessIds.end())
    {
        userInfo = HttpApi::accessIds[token];
        return true;
    }

    token = req.get_header_value("token");
    if(HttpApi::accessIds.find(token) != HttpApi::accessIds.end())
    {
        userInfo = HttpApi::accessIds[token];
        return true;
    }

    token = req.get_header_value("innerFlag");
    if(token == "greatech@234#")
    {
        userInfo.userName = "greatech@234#";
        userInfo.userID = "greatech@234#";
        return true;
    }

    errorRes["Code"] = 401;
    errorRes["Message"] = "未登录，无权访问";

    return false;
}

bool HttpUtil::LogInJudge(const httplib::Request& req, Json::Value& errorRes)
{
    std::string token = req.get_header_value("Token");

    if(HttpApi::accessIds.find(token) != HttpApi::accessIds.end()) return true;

    token = req.get_header_value("token");
    if(HttpApi::accessIds.find(token) != HttpApi::accessIds.end()) return true;

    token = req.get_header_value("innerFlag");
    if(token == "greatech@234#") return true;

    errorRes["Code"] = 401;
    errorRes["Message"] = "未登录，无权访问";

    return false;
}

bool HttpUtil::ReqContentAnalysis(const std::string& content, Json::Value& data, Json::Value& errorRes)
{
    Json::Reader reader;
    if(reader.parse(content, data)) return true;

    //若内容转json失败则返回错误信息
    errorRes["Code"] = 400;
    errorRes["Message"] = "无法解析请求数据，请确认JSON格式是否正确";
    
    return false;
}

HttpUtil* HttpUtil::GetGetInstance()
{
    if(singleObjPtr == nullptr) singleObjPtr = new HttpUtil();
    return singleObjPtr;
}

void HttpUtil::DeleteInstance()
{
    if(singleObjPtr == nullptr) return;
    delete singleObjPtr;
    singleObjPtr = nullptr;
}